package com.icesoft.core.web.excption;

import com.icesoft.core.common.exception.CheckException;
import com.icesoft.core.common.exception.CheckNoLogException;
import com.icesoft.core.common.exception.CodeErrorException;
import com.icesoft.core.common.helper.Resp;
import com.icesoft.core.web.helper.RequestHold;
import com.icesoft.core.web.helper.ResponseUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.client.ResourceAccessException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;

/**
 * @author XHH
 */
@ControllerAdvice
public class GlobalExceptionHandler {
    private static Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @ExceptionHandler(value = {RequestException.class})
    public void checkExceptionErrorHandler(HttpServletRequest request, HttpServletResponse response,
                                           RequestException e) {
        if (e.isLogMsg()) {
            logException(request, e);
        } else {
            logger.trace("发生异常的请求：" + request.getRequestURI(), e);
        }
        ResponseUtils.writeJson(response, Resp.error(e.getMessage()).code(e.getCode()));
    }

    @ExceptionHandler(value = {CodeErrorException.class, CheckException.class, RuntimeException.class})
    public void checkExceptionErrorHandler(HttpServletRequest request, HttpServletResponse response,
                                           RuntimeException e) {
        logException(request, e);
        ResponseUtils.writeJson(response, Resp.error(e));
    }

    @ExceptionHandler(value = {CheckNoLogException.class})
    public void checkNoLogExceptionErrorHandler(HttpServletResponse response,
                                                CheckNoLogException e) {
        ResponseUtils.writeJson(response, Resp.error(e));
    }

    @ExceptionHandler(value = {BindException.class})
    public void defaultErrorHandler(HttpServletRequest request, HttpServletResponse response, BindException e) {
        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
        List<ObjectError> globalErrors = e.getBindingResult().getGlobalErrors();
        StringBuilder sb = new StringBuilder();
        for (ObjectError error : globalErrors) {
            sb.append("[").append(error.getDefaultMessage()).append("]");
        }

        for (FieldError error : fieldErrors) {
            sb.append("[").append(error.getDefaultMessage()).append("]");
        }
        logger.error("数据验证未通过，{}", sb.toString());
        logException(request, e);
        ResponseUtils.writeJson(response, Resp.error("数据验证未通过，" + sb.toString()));
    }

    @ExceptionHandler(value = {MissingServletRequestParameterException.class})
    public void missingServletRequestParameterException(HttpServletRequest request,
                                                        HttpServletResponse response, MissingServletRequestParameterException e) {
        logException(request, e);
        ResponseUtils.writeJson(response, Resp.error("缺少参数" + e.getParameterName()));
    }

    @ExceptionHandler(value = {HttpRequestMethodNotSupportedException.class})
    public void httpRequestMethodNotSupportedException(HttpServletRequest request, HttpServletResponse response,
                                                       HttpRequestMethodNotSupportedException e) {
        logException(request, e);
        ResponseUtils.writeJson(response, Resp.error("不支持的请求类型：" + e.getMethod()));
    }

    @ExceptionHandler(value = {ResourceAccessException.class})
    public void resourceAccessException(HttpServletRequest request, HttpServletResponse response,
                                        ResourceAccessException e) {
        logException(request, e);
        ResponseUtils.writeJson(response, Resp.error("远程服务请求异常"));
    }

    @ExceptionHandler(value = Exception.class)
    public void defaultErrorHandler(HttpServletResponse response, Exception e) {
        logger.error("服务器出错了", e);
        ResponseUtils.writeJson(response, Resp.error("糟糕，服务器出错了~"));
    }

    private void logException(HttpServletRequest request, Exception e) {
        Object param = RequestHold.getRequestParamString(request);
        logger.error("发生异常的请求：{}, 请求参数：{}", request.getRequestURI(), param);
        logger.error("异常信息", e);
    }


}
